package ink.ykb.demo.permission.service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

import ink.ykb.demo.config.CodeConstant;
import ink.ykb.demo.config.MessageUtil;
import ink.ykb.demo.config.ServiceException;
import ink.ykb.demo.permission.dao.DealerDepartmentDao;
import ink.ykb.demo.permission.entity.DealerDepartment;
import ink.ykb.demo.permission.entity.UserDealerDepartment;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
public class DealerDepartmentServiceImpl implements DealerDepartmentService {

	@Autowired
	private MessageUtil messageUtil;
	@Autowired
	private DealerDepartmentDao dealerDepartmentDao;
	@Autowired
	private UserDealerDepartmentService userDealerDepartmentService;
	@Autowired
	private DealerDepartmentService self;
	@Autowired
	private ObjectMapper objectMapper;
	
	@Caching(evict = { 
			@CacheEvict(cacheNames = { "dealerDepartmentList" }, allEntries = true),
			@CacheEvict(cacheNames = { "dealerDepartmentListByParentId" }, allEntries = true)
	})
	@Transactional
	@Override
	public void add(DealerDepartment dealerDepartment) {
		if (dealerDepartment == null) {
			throw new ServiceException(CodeConstant.PARAMS_EMPTY, messageUtil.getMsg(CodeConstant.PARAMS_EMPTY));
		}
		if (dealerDepartment.getName() == null) {
			throw new ServiceException(CodeConstant.PARAMS_EMPTY, messageUtil.getMsg(CodeConstant.PARAMS_EMPTY));
		}
		DealerDepartment dbDealerDepartment = dealerDepartmentDao
				.getDealerDepartmentAndLock(dealerDepartment.getName());
		if (dbDealerDepartment != null) {
			throw new ServiceException(CodeConstant.MUS_110, messageUtil.getMsg(CodeConstant.MUS_110));
		}
		if (dealerDepartment.getParentId() == null) {
			dealerDepartment.setParentId(0L);
		}

		dealerDepartment.setCreateTime(new Date());
		dealerDepartmentDao.insert(dealerDepartment);

	}

	@Caching(evict = { @CacheEvict(cacheNames = { "dealerDepartment" }, key = "#dealerDepartment.id"),
			@CacheEvict(cacheNames = { "dealerDepartmentList" }, allEntries = true) ,
			@CacheEvict(cacheNames = { "dealerDepartmentListByParentId" }, allEntries = true)})
	@Transactional
	@Override
	public void update(DealerDepartment dealerDepartment) {
		if (dealerDepartment == null) {
			throw new ServiceException(CodeConstant.PARAMS_EMPTY, messageUtil.getMsg(CodeConstant.PARAMS_EMPTY));
		}
		if (dealerDepartment.getId() == null) {
			throw new ServiceException(CodeConstant.PARAMS_EMPTY, messageUtil.getMsg(CodeConstant.PARAMS_EMPTY));
		}
		if (dealerDepartment.getName() == null) {
			throw new ServiceException(CodeConstant.PARAMS_EMPTY, messageUtil.getMsg(CodeConstant.PARAMS_EMPTY));
		}

		// 判断code是否重复
		DealerDepartment dbCodeDealerDepartment = dealerDepartmentDao
				.getDealerDepartmentAndLock(dealerDepartment.getName());
		if (dbCodeDealerDepartment != null && !dbCodeDealerDepartment.getId().equals(dealerDepartment.getId())) {
			throw new ServiceException(CodeConstant.MUS_110, messageUtil.getMsg(CodeConstant.MUS_110));
		}

		DealerDepartment dbDealerDepartment = dealerDepartmentDao.getDealerDepartmentById(dealerDepartment.getId());
		if (dbDealerDepartment == null) {
			throw new ServiceException(CodeConstant.MUS_111, messageUtil.getMsg(CodeConstant.MUS_111));
		}

		if (dealerDepartment.getParentId() == null) {
			dealerDepartment.setParentId(0L);
		}

		dbDealerDepartment.setName(dealerDepartment.getName());
		dbDealerDepartment.setParentId(dealerDepartment.getParentId());
		dealerDepartmentDao.updateById(dbDealerDepartment);
	}

	@Caching(evict = { 
			@CacheEvict(cacheNames = { "dealerDepartment" }, allEntries = true),
			@CacheEvict(cacheNames = { "dealerDepartmentList" }, allEntries = true),
			@CacheEvict(cacheNames = { "dealerDepartmentListByParentId" }, allEntries = true)
	})
	@Transactional
	@Override
	public void delete(Long dealerDepartmentId) {
		DealerDepartment dbDealerDepartment = dealerDepartmentDao.getDealerDepartmentById(dealerDepartmentId);
		if (dbDealerDepartment == null) {
			throw new ServiceException(CodeConstant.MUS_111, messageUtil.getMsg(CodeConstant.MUS_111));
		}

		dealerDepartmentDao.deleteById(dbDealerDepartment.getId());

		//递归删除子集部门
		List<DealerDepartment> childList = new ArrayList<>();
		
		List<DealerDepartment> childsTree = this.getDealerDepartmentTree(dealerDepartmentId);
		for (DealerDepartment dd : childsTree) {
			List<DealerDepartment> list = this.getAllByTree(dd);
			childList.addAll(list);
		}
		for (DealerDepartment dealerDepartment : childList) {
			dealerDepartmentDao.deleteById(dealerDepartment.getId());
		}
		
		// 递归删除经销商对应的所有用户关联关系
		List<UserDealerDepartment> userDealerDepartmentList = userDealerDepartmentService
				.getUserDealerDepartmentAll(dealerDepartmentId);
		for (UserDealerDepartment userDealerDepartment : userDealerDepartmentList) {
			userDealerDepartmentService.delete(userDealerDepartment.getId());
		}

		//打印日志
		try {
			String dbDealerDepartmentJson = objectMapper.writeValueAsString(dbDealerDepartment);
			String childsJson = objectMapper.writeValueAsString(childList);
			String userDealerDepartmentListJson = objectMapper.writeValueAsString(userDealerDepartmentList);
			log.warn("\n删除操作\n经销商部门:{}，\n子级经销商部门：{}，\n用户经销商部门关联：{}",
					dbDealerDepartmentJson,childsJson,userDealerDepartmentListJson);
		} catch (JsonProcessingException e) {
			e.printStackTrace();
		}
	}
	
	@Override
	public List<DealerDepartment> getAllByTree(DealerDepartment dealerDepartment){
		List<DealerDepartment> list = new ArrayList<>();
		
		list.add(dealerDepartment);
		
		if(dealerDepartment.getChilds() != null && dealerDepartment.getChilds().size() > 0) {
			for (DealerDepartment dd : dealerDepartment.getChilds()) {
				list.addAll(this.getAllByTree(dd));
			}
		}
		
		return list;
	}

	@Cacheable(cacheNames = "dealerDepartmentList", key = "'dealerDepartmentList'")
	@Override
	public List<DealerDepartment> getDealerDepartmentList() {
		return dealerDepartmentDao.getDealerDepartmentList();
	}

	@Cacheable(cacheNames = "dealerDepartment", key = "#dealerDepartmentId")
	@Override
	public DealerDepartment getDealerDepartment(Long dealerDepartmentId) {
		return dealerDepartmentDao.getDealerDepartmentById(dealerDepartmentId);
	}

	@Cacheable(cacheNames = "dealerDepartmentListByParentId", key = "#parentId")
	@Override
	public List<DealerDepartment> getByParentId(Long parentId) {
		return dealerDepartmentDao.getByParentId(parentId);
	}

	@Override
	public List<DealerDepartment> getDealerDepartmentTree(Long parentId) {
		List<DealerDepartment> dealerDepartmentList = self.getByParentId(parentId);
		for (DealerDepartment dd : dealerDepartmentList) {
			List<DealerDepartment> list = this.getDealerDepartmentTree(dd.getId());
			if (list != null && list.size() > 0) {
				dd.setChilds(list);
			}
		}

		return dealerDepartmentList;
	}

	@Override
	public DealerDepartment getDealerDepartmentTreeByRoot(Long dealerDepartmentId) {
		DealerDepartment dbDealerDepartment = self.getDealerDepartment(dealerDepartmentId);
		if (dbDealerDepartment == null) {
			throw new ServiceException(CodeConstant.MUS_111, messageUtil.getMsg(CodeConstant.MUS_111));
		}
		List<DealerDepartment> childs = this.getDealerDepartmentTree(dealerDepartmentId);
		dbDealerDepartment.setChilds(childs);
		
		//如果不是根节点，循环查询根节点
		DealerDepartment rootDepartment =  this.getDealerDepartmentTreeToRoot(dbDealerDepartment);
		
		return rootDepartment;
	}

	@Override
	public DealerDepartment getDealerDepartmentTreeToRoot(Long dealerDepartmentId) {
		DealerDepartment dbDealerDepartment = self.getDealerDepartment(dealerDepartmentId);
		if (dbDealerDepartment == null) {
			throw new ServiceException(CodeConstant.MUS_111, messageUtil.getMsg(CodeConstant.MUS_111));
		}
		 return this.getDealerDepartmentTreeToRoot(dbDealerDepartment);
	}
	
	@Override
	public DealerDepartment getDealerDepartmentTreeToRoot(DealerDepartment dealerDepartment) {
				//如果不是根节点，循环查询根节点
				DealerDepartment rootDepartment = dealerDepartment;
				while(!rootDepartment.getParentId().equals(0L)) {
					DealerDepartment parent = self.getDealerDepartment(rootDepartment.getParentId());
					if (dealerDepartment == null) {
						throw new ServiceException(CodeConstant.MUS_111, messageUtil.getMsg(CodeConstant.MUS_111));
					}
					List<DealerDepartment> list = new ArrayList<>();
					list.add(rootDepartment);
					parent.setChilds(list);
					
					rootDepartment = parent;
				}
				
				return rootDepartment;
	}

}
